import Component from './Component'
import {wrapToVdom} from './utils';
import PureComponent from './PureComponent';
export {useMemo,useState,useCallback} from './hoooks';

/**
 *
 * @param type 元素类型
 * @param config 配置对象
 * @param children 儿子或儿子们
 */
function createElement(type, config, children) {
  let ref,key;
  if (config) {
    delete config.__source;
    delete config.__self;
    //↑ 这俩源码里用到了 我们暂时用不到 先删除

    ref = config.ref;
    delete config.ref;

    key = config.key;
    delete config.key;
  }

  const props = {...config};
  if (arguments.length > 3) {
    // eslint-disable-next-line prefer-rest-params
    children = Array.prototype.slice.call(arguments, 2);
  }
  props.children = Array.isArray(children)?children.map(wrapToVdom):wrapToVdom(children); //所以... children可能是数组 也可能是个 独生子(对象)

  return {
    type,
    ref, //ref不在props里
    key, //key也不在props里
    props
  }
}

function createRef(){
  return {current: null};
}

function createContext(initialValue={}){

  //const contextValue = {name: 'Person', color: this.state.color, changeColor: this.changeColor}
  //<PersonContext.Provider value={contextValue}>
  //↓也就是将 contextValue 赋给了 Provider._value
  function Provider(props){
    // Provider._value = props.value;

    //↓面这样写 就不用在 Component update里重新给context赋值: this.context = this.constructor.contextType.Provider._value
    //因为 Provider._value 这个对象一直都是同一个(Object.assign是将源对象对象上的属性copy覆盖到目标对象)
    Object.assign(Provider._value||(Provider._value=initialValue), props.value);

    return props.children;
  }

  function Consumer(props){

    return props.children(Provider._value);
  }

  return {Provider,Consumer}
}

function cloneElement(oldElement,newProps,...newChildren){
  //children可能是 一个undefined 一个对象 一个数组 ...
  let children = oldElement.props.children||[];
  children = Array.isArray(children) ? children : [children];

  children.push(...newChildren);
  children = children.map(wrapToVdom)

  children = children.length === 0 ?
    undefined :
    (children.length === 1 ? children[0] : children);

  newProps.children = children;
  const props = {...oldElement.props, ...newProps};

  return {...oldElement,props}
}

export function memo(FunctionComponent){
  return class extends PureComponent {
    render() {
      return FunctionComponent(this.props);
    }
  }
}

const React = {
  createElement,
  Component,
  PureComponent,
  createRef,
  createContext,
  cloneElement,
  memo
}

export default React;
